#include "ffmpegutils.h"
#include <QDebug>
#include <QFile>


FFMPEGUtils::FFMPEGUtils(QObject *parent) : QObject(parent)
{

}

void FFMPEGUtils::resamplePCM()
{

    /**
        struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
                                      int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
                                      int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
                                      int log_offset, void *log_ctx);
     * @brief swr_alloc_set_opts
     */

//    AV_CH_LAYOUT_MONO
    int in_channel_layout = AV_CH_LAYOUT_STEREO;
    AVSampleFormat in_sample_format = AV_SAMPLE_FMT_FLT;

    int in_channel_num = av_get_channel_layout_nb_channels(in_channel_layout);
    int in_sample_bytes = av_get_bytes_per_sample(in_sample_format);
    int in_sample_per_size = in_channel_num * in_sample_bytes;
    const char* in_file_path = "/Users/apple/Documents/ffmpeg/qt/audio/recode_pcm_1618500714.pcm";
    int in_sample_rate = 44100;

    int out_channel_layout = AV_CH_LAYOUT_STEREO;
    AVSampleFormat out_sampele_format = AV_SAMPLE_FMT_S16;
    int out_sample_bytes = av_get_bytes_per_sample(out_sampele_format);
    int out_channel_num = av_get_channel_layout_nb_channels(out_channel_layout);
    int out_sample_per_size = out_sample_bytes * out_channel_num;
    int out_sample_rate = 48000;
    const char* out_file_path = "/Users/apple/Documents/ffmpeg/qt/audio/recode_pcm_48000_2_16.pcm";

    // SwrContext
    SwrContext* swr_context= swr_alloc_set_opts(nullptr,
                               out_channel_layout,out_sampele_format,out_sample_rate,
                                in_channel_layout,in_sample_format,in_sample_rate,
                               0,
                               nullptr);

    if(!swr_context) {


        qDebug() << "swr_alloc_set_opts fail";
        return;
    }

    int swr_init_res = swr_init(swr_context);

    if (swr_init_res < 0) {


        swr_free(&swr_context);
        ERRMES(swr_init_res);
        qDebug() << err_buf;
        return;
    }

    /*
     *
     * int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
                                       int nb_samples, enum AVSampleFormat sample_fmt, int align);
     */
    uint8_t** in_audio_data = nullptr;
    int in_linesize = 0;
    int in_samples = 1024;
    int samples_alloc_res = av_samples_alloc_array_and_samples(&in_audio_data,
                                                               &in_linesize,
                                                               in_channel_num,
                                                               in_samples,
                                                               in_sample_format,
                                                               1);
    if(samples_alloc_res < 0) {

        swr_free(&swr_context);
        ERRMES(samples_alloc_res);
        qDebug() << "av_samples_alloc_array_and_samples " <<  err_buf;
        return;
    }


    uint8_t** out_audio_data = nullptr;
    int out_linesize = 0;
    /*
        int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) av_const;
    */
    int out_sample = av_rescale_rnd(out_sample_rate, in_samples,in_sample_rate,AV_ROUND_UP);



   samples_alloc_res = av_samples_alloc_array_and_samples(&out_audio_data,
                                       &out_linesize,
                                       out_channel_num,
                                       out_sample,
                                       out_sampele_format,
                                       1);
    if(samples_alloc_res < 0) {

        ERRMES(samples_alloc_res);
        qDebug() << "av_samples_alloc_array_and_samples " << err_buf;


        av_freep(in_audio_data);
        av_freep(&in_audio_data);
        swr_free(&swr_context);
        return;
    }


    QFile in_file(in_file_path);

    if(!in_file.open(QFile::ReadOnly)) {


        qDebug() << "in file error";

        av_freep(out_audio_data);
        av_freep(&out_audio_data);
        av_freep(in_audio_data);
        av_freep(&in_audio_data);
        swr_free(&swr_context);

        return;
    }


    QFile out_file(out_file_path);

    if(!out_file.open(QFile::WriteOnly)) {


        qDebug() << "out file error";

        in_file.close();

        av_freep(out_audio_data[0]);
        av_freep(out_audio_data);

        av_freep(in_audio_data[0]);
        av_freep(in_audio_data);

        swr_free(&swr_context);

        return;
    }


    int len = 0;

    while ((len = in_file.read((char *)in_audio_data[0],in_linesize)) > 0) {

        in_samples = len / in_sample_per_size;

        /**
            int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
                                const uint8_t **in , int in_count);
        */
        qDebug() << "in samples " << in_samples;
        // 返回转换的样本数量
       int out_samples_size = swr_convert(swr_context,
                                          out_audio_data,
                                          out_sample,
                                          (const uint8_t **)in_audio_data,
                                          in_samples);

       if(out_samples_size < 0) {

           qDebug() << "swr_convert fail";
           break;
       }

       out_file.write((char *)out_audio_data[0], out_samples_size * out_sample_per_size);
    }


    while((len = swr_convert(swr_context,out_audio_data,out_sample,nullptr,0)) > 0) {

        qDebug() << "remainder " << len;
        out_file.write((char *)out_audio_data[0], len * out_sample_per_size);
    }


    in_file.close();
    out_file.close();

    if (in_audio_data) {

        av_freep(&in_audio_data[0]);
    }

    av_freep(&in_audio_data);

    if (out_audio_data) {

        av_freep(&out_audio_data[0]);
    }

    av_freep(&out_audio_data);
    swr_free(&swr_context);
}

void FFMPEGUtils::resamplePCM(ResampleStruct &in, ResampleStruct &out)
{

    int in_num_channel = av_get_channel_layout_nb_channels(in.channel_layout);
    int in_per_sample_bytes = in_num_channel * av_get_bytes_per_sample(in.sample_format);


    int out_num_channel = av_get_channel_layout_nb_channels(out.channel_layout);
    int out_per_sample_bytes = out_num_channel * av_get_bytes_per_sample(out.sample_format);

    /*
     * struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
                                      int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
                                      int64_t  in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
                                      int log_offset, void *log_ctx);
    */
    SwrContext* swr_context = swr_alloc_set_opts(nullptr,
                                                   out.channel_layout,out.sample_format,out.sample_rate,
                                                   in.channel_layout,in.sample_format,in.sample_rate,
                                                   0,
                                                   nullptr
                                                   );

    if(swr_context == nullptr) {

        qDebug() << "swr_alloc_set_opts fail";
        return;
    }

    int res = swr_init(swr_context);

    if(res < 0) {


        swr_free(&swr_context);
        ERRMES(res);
        qDebug() << err_buf;
        return;
    }

    /*
     *
     * int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels,
                                       int nb_samples, enum AVSampleFormat sample_fmt, int align);
     */
    uint8_t** in_audio_data = nullptr;
    int in_linesize = 0;
    int in_samples = 1024;
    int samples_alloc_res = av_samples_alloc_array_and_samples(&in_audio_data,
                                                               &in_linesize,
                                                               in_num_channel,
                                                               in_samples,
                                                               in.sample_format,
                                                               1);
    if(samples_alloc_res < 0) {

        swr_free(&swr_context);
        ERRMES(samples_alloc_res);
        qDebug() << "av_samples_alloc_array_and_samples " <<  err_buf;
        return;
    }


    uint8_t** out_audio_data = nullptr;
    int out_linesize = 0;
    /*
        int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) av_const;
    */
    int out_sample = av_rescale_rnd(out.sample_rate, in_samples,in.sample_rate,AV_ROUND_UP);
   samples_alloc_res = av_samples_alloc_array_and_samples(&out_audio_data,
                                       &out_linesize,
                                       out_num_channel,
                                       out_sample,
                                       out.sample_format,
                                       1);
    if(samples_alloc_res < 0) {

        ERRMES(samples_alloc_res);
        qDebug() << "av_samples_alloc_array_and_samples " << err_buf;


        av_freep(in_audio_data);
        av_freep(&in_audio_data);
        swr_free(&swr_context);
        return;
    }


    QFile in_file(in.pcm_file);

    if(!in_file.open(QFile::ReadOnly)) {


        qDebug() << "in file error";

        av_freep(out_audio_data);
        av_freep(&out_audio_data);
        av_freep(in_audio_data);
        av_freep(&in_audio_data);
        swr_free(&swr_context);

        return;
    }


    QFile out_file(out.pcm_file);

    if(!out_file.open(QFile::WriteOnly)) {


        qDebug() << "out file error";

        in_file.close();

        if(out_audio_data[0] != nullptr) {

            av_freep(&out_audio_data[0]);
        }

        av_freep(&out_audio_data);

        if(in_audio_data) {

            av_freep(&in_audio_data[0]);
        }
        av_freep(&in_audio_data);
        swr_free(&swr_context);

        return;
    }


    int len = 0;

    while ((len = in_file.read((char *)in_audio_data[0],in_linesize)) > 0) {

        in_samples = len / in_per_sample_bytes;

        /**
            int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
                                const uint8_t **in , int in_count);
        */
        qDebug() << "in samples " << in_samples;
        // 返回转换的样本数量
       int out_samples_size = swr_convert(swr_context,
                                          out_audio_data,
                                          out_sample,
                                          (const uint8_t **)in_audio_data,
                                          in_samples);

       if(out_samples_size < 0) {

           qDebug() << "swr_convert fail";
           break;
       }

       out_file.write((char *)out_audio_data[0], out_samples_size * out_per_sample_bytes);
    }


    while((len = swr_convert(swr_context,out_audio_data,out_sample,nullptr,0)) > 0) {

        qDebug() << "remainder " << len;
        out_file.write((char *)out_audio_data[0], len * out_per_sample_bytes);
    }


    in_file.close();
    out_file.close();

    // av_freep 传递要释放的指针的指针，指针释放之后，把指针的地址设置为 NULL
    if (in_audio_data) {


        av_freep(&in_audio_data[0]);
    }

    av_freep(&in_audio_data);

    if (out_audio_data) {

        av_freep(&out_audio_data[0]);
    }

    av_freep(&out_audio_data);
    swr_free(&swr_context);

//    int* p = (int *)malloc(sizeof(int) * 10);

//    free(p);

//    int** p1 = (int **)malloc(sizeof(int *) * 10);

}
